package com.onLineCar.es.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.godGuang.common.core.domain.PageResult;



import com.onLineCar.es.domain.Content;
import com.onLineCar.es.domain.request.RequestContent;
import com.onLineCar.es.service.EsService;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author : 段敏强
 * @className : EsServerImpl
 * @description : 描述说明该类的功能
 * @createTime : 2024/01/10 09:15
 */

/**
 * ES服务实现类
 */

@Service
public class EsServerImpl implements EsService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    private static final String PATIENTS_KEY = "patients";


    /**
     * 将数据库中的数据同步到Elasticsearch中。
     *
     * @param list 要同步的数据列表
     */
    @Override
    public void esAdd(List<Content> list) {
        // 创建一个批量请求对象
        BulkRequest bulkRequest = new BulkRequest(PATIENTS_KEY);
        // 遍历数据列表，为每个数据添加到批量请求中
        list.forEach(content -> {
            // 添加一个索引请求到批量请求中
            bulkRequest.add(new IndexRequest(PATIENTS_KEY)
                    // 设置索引请求的ID为内容的ID
                    .id(String.valueOf(content.getContentId()))
                    // 将内容转换为JSON字符串，并设置为请求的源数据
                    .source(JSONObject.toJSONString(content), XContentType.JSON));
        });
        try {
            // 执行批量请求，将数据同步到Elasticsearch中
            restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            // 抛出运行时异常，表示发生IO异常
            throw new RuntimeException(e);
        }
    }




    /**
     * 获取内容列表
     *
     * @param requestContent 请求参数
     * @return 返回包含内容分页结果的对象
     */
    @Override
    public PageResult<Content> list(RequestContent requestContent) {
        // 获取总记录数
        long total = 0;
        // 创建内容列表
        ArrayList<Content> contents = new ArrayList<Content>();
        try {
            // 创建搜索请求
            SearchRequest searchRequest = new SearchRequest(PATIENTS_KEY);
            // 创建搜索源构建器
            SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.searchSource();
            // 创建布尔查询构建器
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
            // 如果请求参数中的内容标题不为空，则添加匹配查询条件
            if (StringUtils.isNoneEmpty(requestContent.getContentTitle())) {
                // 设置内容标题匹配查询条件
                boolQuery.must(QueryBuilders.matchQuery("contentTitle", requestContent.getContentTitle()));
            }
//            // 如果请求参数中的目录ID为空，则添加匹配查询条件
//            if (null == requestContent.getCatalogueId()) {
//                // 设置目录ID匹配查询条件
//                boolQuery.must(QueryBuilders.matchQuery("catalogueId", 1));
//            }
//            // 如果请求参数中的目录ID不为空，则添加匹配查询条件
//            if (null != requestContent.getCatalogueId()) {
//                // 设置目录ID匹配查询条件
//                boolQuery.must(QueryBuilders.matchQuery("catalogueId", requestContent.getCatalogueId()));
//            }
            // 设置查询条件
            searchSourceBuilder.query(boolQuery);
            // 设置分页参数，从第几页开始，每页多少条记录
            searchSourceBuilder.from((requestContent.getPageNum() - 1) * requestContent.getPageSize());
            // 设置每页多少条记录
            searchSourceBuilder.size(requestContent.getPageSize());
            // 创建高亮显示构建器
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            // 设置高亮显示参数，对标题进行高亮显示
            HighlightBuilder contentTitle = highlightBuilder.field("contentTitle").preTags("<font style =\" color : red ;\">").postTags("</font>");
            // 设置高亮显示参数，对标题进行高亮显示
            searchSourceBuilder.highlighter(contentTitle);
            // 设置搜索请求的源构建器
            searchRequest.source(searchSourceBuilder);
            // 执行搜索请求，获取搜索响应结果
            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 获取搜索结果中的命中记录数和命中记录列表
            SearchHits searchHits = search.getHits();
            total = searchHits.getTotalHits().value;
            // 获取所有命中记录的ID和源字符串数据
            SearchHit[] hits = searchHits.getHits();
            // 遍历命中记录列表，获取命中记录的源字符串数据，并将源字符串数据解析为内容对象，并设置内容ID属性值
            for (SearchHit hit : hits) {
                String asString = hit.getSourceAsString();
                // 将源字符串数据解析为内容对象，并设置内容ID属性值
                Content content = JSONObject.parseObject(asString, Content.class);
                // 获取命中记录的ID，并设置内容ID属性值
                content.setContentId(Integer.valueOf(hit.getId()));
                // 获取命中记录的高亮字段信息，如果存在则进行高亮显示处理，并设置内容标题属性值
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                // 如果命中记录的高亮字段信息不为空，则进行高亮显示处理
                if (null != highlightFields){
                    // 获取命中记录的高亮字段信息，并获取contentTitle字段的高亮文本
                    HighlightField highlightField = highlightFields.get("contentTitle");
                    // 如果highlightField不为空，则进行高亮显示处理
                    if (null != highlightField){
                        // 获取命中的高亮文本列表
                        Text[] fragments = highlightField.fragments();
                        // 创建一个字符串变量，用于存储高亮文本
                        String str ="";
                        // 遍历高亮文本列表，将高亮文本拼接成字符串
                        for (Text fragment : fragments) {
                            // 将高亮文本拼接成字符串
                            str += fragment;
                        }
                        // 设置内容标题属性值
                        content.setContentTitle(str);
                    }
                }
                // 将内容对象添加到内容列表中
                contents.add(content);
            }
            // 返回包含内容分页结果的对象，包括总记录数和内容列表数据
        } catch (IOException e) {
            // 抛出运行时异常，表示发生IO异常
            throw new RuntimeException(e);
        }
        // 返回包含内容分页结果的对象，包括总记录数和内容列表数据
        return PageResult.toPageResult(total, contents);
    }

}
